package com.example.previewvideo;

import android.Manifest;
import android.content.pm.PackageManager;
import android.graphics.ImageFormat;
import android.graphics.SurfaceTexture;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.TotalCaptureResult;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.media.Image;
import android.media.ImageReader;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.HandlerThread;
import android.util.Log;
import android.util.Size;
import android.view.Surface;
import android.view.TextureView;
import android.widget.Button;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;

import com.blankj.utilcode.util.CollectionUtils;
import com.blankj.utilcode.util.LogUtils;
import com.example.demo.R;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;

public class Camera2Activity extends AppCompatActivity {

    private static final String TAG = "Camera2Activity";
    private static final int REQUEST_CAMERA_PERMISSION = 200;

    private CameraDevice cameraDevice;
    private CameraCaptureSession captureSession;
    private CaptureRequest.Builder captureRequestBuilder;
    private ImageReader imageReader;
    private TextureView textureView;
    private Handler backgroundHandler;
    private HandlerThread backgroundThread;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_camera2capture);

        textureView = findViewById(R.id.surface_view);
        Button captureButton = findViewById(R.id.capture_button);
//        textureView.setSurfaceTextureListener(textureListener);


        captureButton.setOnClickListener(v -> capturePhoto());

        String directoryPath = getCacheDir().getAbsolutePath() + "/videoNameA/";
        File mediaStorageDir = new File(directoryPath);
        if (!mediaStorageDir.exists()) {
            if (!mediaStorageDir.mkdirs()) {
                return;
            }
        }
//
//        String path = getExternalCacheDir().getPath();
        LogUtils.i(TAG + "path：" + directoryPath);

        getAllDataFileName(directoryPath);


    }




    //测试获取文件下的子文件夹
    public ArrayList<String> getAllDataFileName(String folderPath) {
        ArrayList<String> fileList = new ArrayList<>();
        File file = new File(folderPath);
        File[] tempList = file.listFiles();

        if (tempList == null) {
            return null;
        }

        for (int i = 0; i < tempList.length; i++) {

            if (tempList[i].isFile()) {
                Log.i(TAG + "文 件：", tempList[i].getName());
//                String fileName = tempList[i].getName();
            } else {
                Log.i(TAG + "文件夹：", tempList[i].getName());

            }
        }
        return fileList;
    }


    //https://blog.51cto.com/u_14276/10460561
    private final TextureView.SurfaceTextureListener textureListener = new TextureView.SurfaceTextureListener() {
        @Override
        public void onSurfaceTextureAvailable(@NonNull SurfaceTexture surface, int width, int height) {
            setUpCamera();
        }

        @Override
        public void onSurfaceTextureSizeChanged(@NonNull SurfaceTexture surface, int width, int height) {
            // Handle size changes if necessary
        }

        @Override
        public boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surface) {
            // Cleanup if necessary
            return true;
        }

        @Override
        public void onSurfaceTextureUpdated(@NonNull SurfaceTexture surface) {
            // Handle updates if necessary
        }
    };

    private Size imageSize;
    private Size previewSize;

    private void setUpCamera() {
        startBackgroundThread();

        CameraManager cameraManager = (CameraManager) getSystemService(CAMERA_SERVICE);
        try {
            String cameraId = cameraManager.getCameraIdList()[0];

            CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraId);
            StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);

            Size[] previewSizes = map.getOutputSizes(SurfaceTexture.class);

            Size[] imageSizes = map.getOutputSizes(ImageFormat.JPEG);

            previewSize = chooseOptimalSize(previewSizes, textureView.getWidth(), textureView.getHeight());

            imageSize = chooseOptimalSize(imageSizes, 1920, 1080); // For example, choose 1920x1080 for images

            // Choose the best size based on your requirements

            LogUtils.i(TAG + " chooseOptimalSize getWidth :" + imageSize.getWidth() + " getHeight: " + imageSize.getHeight());


//            imageReader = ImageReader.newInstance(640, 480, ImageFormat.JPEG, 1);

            imageReader = ImageReader.newInstance(imageSize.getWidth(), imageSize.getHeight(), ImageFormat.JPEG, 1);

            imageReader.setOnImageAvailableListener(this::onImageAvailable, backgroundHandler);

            if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
                // TODO: Consider calling
                //    ActivityCompat#requestPermissions
                // here to request the missing permissions, and then overriding
                //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
                //                                          int[] grantResults)
                // to handle the case where the user grants the permission. See the documentation
                // for ActivityCompat#requestPermissions for more details.
                return;
            }
            cameraManager.openCamera(cameraId, new CameraDevice.StateCallback() {
                @Override
                public void onOpened(@NonNull CameraDevice camera) {
                    cameraDevice = camera;
                    createCameraPreviewSession();
                }

                @Override
                public void onDisconnected(@NonNull CameraDevice camera) {
                    camera.close();
                    cameraDevice = null;
                }

                @Override
                public void onError(@NonNull CameraDevice camera, int error) {
                    camera.close();
                    cameraDevice = null;
                }
            }, backgroundHandler);

        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    private void createCameraPreviewSession() {
        try {
//            SurfaceTexture surfaceTexture = textureView.getSurfaceTexture();
//            surfaceTexture.setDefaultBufferSize(640, 480);
//            Surface surface = new Surface(surfaceTexture);

            SurfaceTexture surfaceTexture = textureView.getSurfaceTexture();
            surfaceTexture.setDefaultBufferSize(500, 500);
            Surface surface = new Surface(surfaceTexture);
            Surface imageReaderSurface = imageReader.getSurface();


            captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
            // 把图像读取器添加到预览目标
            captureRequestBuilder.addTarget(surface);
//            // 设置自动对焦模式
//            captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
//                    CaptureRequest.CONTROL_AF_MODE_AUTO);
//            // 设置自动曝光模式
//            captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
//                    CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
//            // 开始对焦
//            captureRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
//                    CameraMetadata.CONTROL_AF_TRIGGER_START);


            captureRequestBuilder.set(CaptureRequest.JPEG_ORIENTATION, getOrientation());


            cameraDevice.createCaptureSession(
                    Arrays.asList(surface, imageReaderSurface)
                    ,
                    new CameraCaptureSession.StateCallback() {
                        @Override
                        public void onConfigured(@NonNull CameraCaptureSession session) {
                            captureSession = session;
                            updatePreview();
                        }

                        @Override
                        public void onConfigureFailed(@NonNull CameraCaptureSession session) {
                            Toast.makeText(Camera2Activity.this, "Configuration change", Toast.LENGTH_SHORT).show();
                        }
                    }, backgroundHandler);

        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    private void updatePreview() {
        if (cameraDevice == null) return;
        captureRequestBuilder.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_AUTO);
        try {
            captureSession.setRepeatingRequest(captureRequestBuilder.build(), null, backgroundHandler);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    private void capturePhoto() {
        if (cameraDevice == null) return;

        try {
            CaptureRequest.Builder captureBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
            captureBuilder.addTarget(imageReader.getSurface());


            // Set the orientation of the captured image
            captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, getOrientation());

            // Stop the repeating request and capture the photo

            captureSession.stopRepeating();
            captureSession.abortCaptures();
            captureSession.capture(captureBuilder.build(), new CameraCaptureSession.CaptureCallback() {
                @Override
                public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) {
                    Toast.makeText(Camera2Activity.this, "Photo captured!", Toast.LENGTH_SHORT).show();

                    // Restart the preview after capturing
                    updatePreview();

                }
            }, backgroundHandler);

        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }


    private int getOrientation() {
        // Get the current device orientation
        int rotation = getWindowManager().getDefaultDisplay().getRotation();
        int orientation = 0;
        switch (rotation) {
            case Surface.ROTATION_0:
                orientation = 90;
                break;
            case Surface.ROTATION_90:
                orientation = 0;
                break;
            case Surface.ROTATION_180:
                orientation = 270;
                break;
            case Surface.ROTATION_270:
                orientation = 180;
                break;
        }
        return orientation;
    }

    private void onImageAvailable(ImageReader reader) {
        Image image = reader.acquireLatestImage();
        if (image == null) return;

        ByteBuffer buffer = image.getPlanes()[0].getBuffer();
        byte[] bytes = new byte[buffer.remaining()];
        buffer.get(bytes);

        saveImage(bytes);
        image.close();
    }

    private void saveImage(byte[] bytes) {
        File file = new File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), "photo.jpg");
        try (FileOutputStream output = new FileOutputStream(file)) {
            output.write(bytes);
            LogUtils.i("saveImage: " + file.getAbsolutePath());
//            Toast.makeText(this, "Image saved: " + file.getAbsolutePath(), Toast.LENGTH_LONG).show();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void startBackgroundThread() {
        backgroundThread = new HandlerThread("CameraBackground");
        backgroundThread.start();
        backgroundHandler = new Handler(backgroundThread.getLooper());
    }

    private void stopBackgroundThread() {
        if (backgroundThread != null) {
            backgroundThread.quitSafely();
            try {
                backgroundThread.join();
                backgroundThread = null;
                backgroundHandler = null;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
//        if (captureSession != null) {
//            captureSession.close();
//            captureSession = null;
//        }
//        if (cameraDevice != null) {
//            cameraDevice.close();
//            cameraDevice = null;
//        }
//        stopBackgroundThread();
    }


    private Size chooseOptimalSize(Size[] choices, int width, int height) {
        // Select a size that is closest to the desired width and height
        Size optimalSize = choices[0];
        for (Size size : choices) {
            if (size.getHeight() == height && size.getWidth() == width) {
                return size;
            }
            if (size.getHeight() >= height && size.getWidth() >= width) {
                if (optimalSize.getHeight() < height || optimalSize.getWidth() < width) {
                    optimalSize = size;
                }
            }
        }
        return optimalSize;
    }


    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == REQUEST_CAMERA_PERMISSION) {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                setUpCamera();
            } else {
                Toast.makeText(this, "Camera permission denied", Toast.LENGTH_SHORT).show();
            }
        }
    }
}
